/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "imageknife_task_internal.h"
#include "downsampling/down_sampler.h"
#include "imageknife_internal.h"
#include "request/imageknife_request_internal.h"
#include "utils/file_type_util.h"
#include <sstream>

namespace ImageKnifePro {

DecodeImageSource::DecodeImageSource(uint8_t *buffer, uint32_t length)
{
    errorCode_ = OH_ImageSourceNative_CreateFromData(buffer, length, &imageSource_);
    if (errorCode_ != IMAGE_SUCCESS) {
        imageSource_ = nullptr;
    }
}

DecodeImageSource::~DecodeImageSource()
{
    if (imageSource_ != nullptr) {
        OH_ImageSourceNative_Release(imageSource_);
    }
}

Image_ErrorCode DecodeImageSource::GetErrorCode() const
{
    return errorCode_;
}

OH_ImageSourceNative *DecodeImageSource::GetImageSourceNative() const
{
    return imageSource_;
}

ImageKnifeTaskInternal::ImageKnifeTaskInternal(std::shared_ptr<uint8_t[]> buffer, uint32_t bufferLength,
    uint32_t frameIndex, ImageRequestType type, std::shared_ptr<ImageKnifeRequestInternal> request)
    : frameIndex_(frameIndex), type_(type), request_(request), isFrameDecodeMode_(true)
{
    product.imageBuffer = buffer;
    product.imageLength = bufferLength;
}

std::string ImageKnifeTaskInternal::GetTaskInfo(ImageRequestType type,
                                                std::shared_ptr<ImageKnifeRequestInternal> request)
{
    IMAGE_KNIFE_CHECK_RETURN(request == nullptr, "[Null Request] ");

    std::string source;
    switch (type) {
        case ImageRequestType::MAIN_SRC:
            source = "MainSrc";
            break;
        case ImageRequestType::PLACE_SRC:
            source = "PlaceSrc";
            break;
        case ImageRequestType::THUMBNAIL_SRC:
            source = "ThumbnailSrc";
            break;
        case ImageRequestType::ERROR_SRC:
            source = "ErrorSrc";
            break;
        default:
            break;
    }

    if (request->IsPreload()) {
        return "[ID:" + request->GetNodeId() + " Animator:" + std::to_string(request->IsPreloadAnimator()) +
               " Type:" + source + "] ";
    }

    return "[ID:" + request->GetNodeId() + " VersionID:" + std::to_string(request->GetVersion()) +
           " Type:" + source + "] ";
}

std::string ImageKnifeTaskInternal::GetTaskInfo() const
{
    return GetTaskInfo(type_, request_);
}

std::string ImageKnifeTaskInternal::GetDisplayPixelmapInfo() const
{
    IMAGE_KNIFE_CHECK_RETURN(product.imageDataCache == nullptr, "Null Image DataCache");
    auto dataCache = std::dynamic_pointer_cast<ImageDataCacheInternal>(product.imageDataCache);
    IMAGE_KNIFE_CHECK_RETURN(dataCache == nullptr, "Null Image DataCacheInternal");
    auto pixelmapSize = dataCache->GetPixelmapSize();
    std::ostringstream res;
    res << GetTaskInfo();
    res << " Pixelmap Ready, origin width:" << dataCache->imageWidth << " origin height:" << dataCache->imageHeight
        << " pixelmap width:" << pixelmapSize.width << " pixelmap height:" << pixelmapSize.height
        << " cache size:" << dataCache->GetImageCacheSize() << " format:" << static_cast<int>(dataCache->type);
    return res.str();
}

void ImageKnifeTaskInternal::SetIsAnimator()
{
    IMAGE_KNIFE_CHECK(request_ == nullptr);
    if (request_->IsPreload()) {
        isAnimator_ = request_->IsPreloadAnimator();
        return;
    }

    auto imageNode = ImageKnifeInternal::GetInstance().GetImageNode(request_->GetNodeId());
    if (imageNode != nullptr) {
        isAnimator_ = imageNode->IsAnimator();
        return;
    }

    // 预创建组件非Animator组件
    isAnimator_ = false;
}

ImageFormat ImageKnifeTaskInternal::GetImageBufferFormat() const
{
    return imageBufferFormat_;
}

ImageSource *ImageKnifeTaskInternal::GetImageSource() const
{
    return imageSrc_;
}

ImageRequestType ImageKnifeTaskInternal::GetImageRequestType() const
{
    return type_;
}

std::shared_ptr<ImageKnifeRequest> ImageKnifeTaskInternal::GetImageKnifeRequest() const
{
    return request_;
}

void ImageKnifeTaskInternal::SetImageFormat(ImageFormat format)
{
    imageBufferFormat_ = format;
}

void ImageKnifeTaskInternal::SetDecodeImageSource(std::shared_ptr<DecodeImageSource> decodeImageSource)
{
    if (decodeImageSource == nullptr) {
        EchoError("Get Empty DecodeImageSource");
        return;
    }

    decodeImageSource_ = decodeImageSource;
    if (decodeImageSource_->GetImageSourceNative() == nullptr) {
        EchoError("Get Bad DecodeImageSource: " + std::to_string(decodeImageSource_->GetErrorCode()));
    }
}

std::shared_ptr<DecodeImageSource> ImageKnifeTaskInternal::GetDecodeImageSource() const
{
    return decodeImageSource_;
}

void ImageKnifeTaskInternal::SetDesiredSize(Image_Size desiredSize)
{
    desiredImageSize_ = desiredSize;
}

void ImageKnifeTaskInternal::MarkDecodeFrameFinished()
{
    isDecodeFrameFinished_ = true;
}

bool ImageKnifeTaskInternal::IsDecodeFrameFinished() const
{
    return isDecodeFrameFinished_;
}

int ImageKnifeTaskInternal::GetDecodeFrameIndex() const
{
    if (!isFrameDecodeMode_ && isAnimationImage_) {
        return -1;
    }
    return frameIndex_;
}

bool ImageKnifeTaskInternal::IsFrameDecodeMode() const
{
    return isFrameDecodeMode_;
}

void ImageKnifeTaskInternal::CheckDecodeMode(const uint32_t &width, const uint32_t &height)
{
    // animator组件必须使用pixelmap列表，即不支持逐帧解码
    if (isAnimator_) {
        return;
    }

    IMAGE_KNIFE_CHECK(request_ == nullptr);
    auto option = request_->GetImageKnifeOption();
    IMAGE_KNIFE_CHECK(option == nullptr);
    IMAGE_KNIFE_CHECK(decodeImageSource_ == nullptr || decodeImageSource_->GetImageSourceNative() == nullptr);

    const size_t maxSize =  720 * 720 * 32;
    if (option->animationDecodeMode == AnimationDecodeMode::FRAME_MODE ||
        (option->animationDecodeMode == AnimationDecodeMode::AUTO && (width * height * frameCount_ > maxSize))) {
        // 确认解码模式
        isFrameDecodeMode_ = true;
        int *delayTimeList = new int[frameCount_];
        auto errorCode = OH_ImageSourceNative_GetDelayTimeList(decodeImageSource_->GetImageSourceNative(),
            delayTimeList, frameCount_);
        if (errorCode != IMAGE_SUCCESS) {
            EchoError("Get DelayTimeList Failed, error code: " + std::to_string(errorCode));
            delete [] delayTimeList;
            return;
        }
        auto dataCache = std::make_shared<ImageDataCacheInternal>(product.imageBuffer, product.imageLength,
            option, frameCount_, delayTimeList);
        dataCache->requestType = type_;
        dataCache->type = imageBufferFormat_;
        dataCache->SetDesiredSize(desiredImageSize_);
        product.imageDataCache = dataCache;
    }
}

void ImageKnifeTaskInternal::QueryImageBufferFormat()
{
    if (product.imageBuffer == nullptr) {
        EchoError("Empty Image Buffer (Query Image Format)");
        imageBufferFormat_ = ImageFormat::UNKNOWN;
        return;
    }

    imageBufferFormat_ = FileTypeUtil::CheckImageFormat(product.imageBuffer.get(), product.imageLength);
    decodeImageSource_ = std::make_shared<DecodeImageSource>(product.imageBuffer.get(), product.imageLength);
    auto imgErrorCode = decodeImageSource_->GetErrorCode();
    if (imgErrorCode != IMAGE_SUCCESS) {
        EchoError("Create ImageSource failed, error code: " + std::to_string(imgErrorCode));
        return;
    }
    auto imageSource = decodeImageSource_->GetImageSourceNative();

    // 创建定义图片信息的结构体对象，并获取图片信息
    OH_ImageSource_Info *imageInfo;
    OH_ImageSourceInfo_Create(&imageInfo);
    imgErrorCode = OH_ImageSourceNative_GetImageInfo(imageSource, 0, imageInfo);
    if (imgErrorCode != IMAGE_SUCCESS) {
        EchoError("Failed to get imageInfo");
        return;
    }

    // 获取宽和高
    uint32_t width;
    uint32_t height;
    OH_ImageSourceInfo_GetWidth(imageInfo, &width);
    OH_ImageSourceInfo_GetHeight(imageInfo, &height);
    OH_ImageSourceInfo_Release(imageInfo);

    // 根据图片帧树判断图片格式，帧数大于1视为动图
    imgErrorCode = OH_ImageSourceNative_GetFrameCount(imageSource, &frameCount_);
    if (imgErrorCode != IMAGE_SUCCESS || frameCount_ < 1) {
        EchoError("Get FrameCount Failed, error code: " + std::to_string(imgErrorCode));
    } else if (frameCount_ > 1) {
        isAnimationImage_ = true;
        CheckDecodeMode(width, height);
    }

    if (type_ == ImageRequestType::MAIN_SRC) {
        // 请求数据采集，记录主图信息
        IMAGE_KNIFE_CHECK(request_ == nullptr);
        request_->GetImageInfo().imageHeight = height;
        request_->GetImageInfo().imageWidth = width;
        request_->GetImageInfo().bufSize = product.imageLength;
        request_->GetImageInfo().type = imageBufferFormat_;
        request_->GetImageInfo().frameCount = frameCount_;

        // 降采样，解码期望宽高计算
        auto option = request_->GetImageKnifeOption();
        IMAGE_KNIFE_CHECK(option == nullptr);
        desiredImageSize_ = DownSampler::CalculateSize(imageBufferFormat_, {.width = width, .height = height},
                                                       request_->GetRequestImageSize(), option->downSampling);
        IMAGE_KNIFE_LOG(LOG_DEBUG, "%{public}s DownSampling Strategy:%{public}d Desired Size: %{public}d, %{public}d",
                        GetTaskInfo().c_str(), static_cast<int>(option->downSampling),
                        desiredImageSize_.width, desiredImageSize_.height);
    }
}

std::shared_ptr<ImageKnifeRequestInternal> ImageKnifeTaskInternal::GetImageKnifeRequestInternal() const
{
    return request_;
}

OH_ImageSourceNative *ImageKnifeTaskInternal::GetImageSourceNative() const
{
    if (decodeImageSource_ == nullptr) {
        return nullptr;
    }

    return decodeImageSource_->GetImageSourceNative();
}

uint32_t ImageKnifeTaskInternal::GetImageSourceFrameCount() const
{
    return frameCount_;
}

Image_Size ImageKnifeTaskInternal::GetDesiredImageSize() const
{
    return desiredImageSize_;
}

void ImageKnifeTaskInternal::SetFallbackUrl(std::string fallbackUrl)
{
    fallbackUrl_.SetString(fallbackUrl);
    imageSrc_ = &fallbackUrl_;
}

bool ImageKnifeTaskInternal::IsFileCacheNeedRename() const
{
    return fileCacheNeedRename_;
}

void ImageKnifeTaskInternal::MarkFileCacheNeedRename()
{
    fileCacheNeedRename_ = true;
}
} // end of namespace
